package collectors

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/go-kit/kit/log"
	"github.com/go-kit/kit/transport"
	kithttp "github.com/go-kit/kit/transport/http"
	"github.com/go-playground/validator/v10"
	"github.com/gorilla/mux"
	"mime/multipart"
	"net/http"
)

const DefaultDataSource = "微信"

func NewHandler(logger log.Logger, validate *validator.Validate, svc CollectorService) *mux.Router {
	opts := []kithttp.ServerOption{
		kithttp.ServerErrorHandler(transport.NewLogErrorHandler(logger)),
		kithttp.ServerErrorEncoder(errorEncoder),
	}

	reportMessageHandler := kithttp.NewServer(
		makeReportMessageEndpoint(svc),
		makeDecodeReportMessageRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportUploadHandler := kithttp.NewServer(
		makeReportUploadEndpoint(svc),
		makeDecodeReportUploadRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportCollectorJoinChatroomHandler := kithttp.NewServer(
		makeReportCollectorJoinChatroomEndpoint(svc),
		makeDecodeReportCollectorJoinChatroomRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportCollectorLeaveChatroomHandler := kithttp.NewServer(
		makeReportCollectorLeaveChatroomEndpoint(svc),
		makeDecodeReportCollectorLeaveChatroomRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportMemberJoinChatroomHandler := kithttp.NewServer(
		makeReportMemberJoinChatroomEndpoint(svc),
		makeDecodeReportMemberJoinChatroomRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportMemberLeaveChatroomHandler := kithttp.NewServer(
		makeReportMemberLeaveChatroomEndpoint(svc),
		makeDecodeReportMemberLeaveChatroomRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportChatroomMemberHandler := kithttp.NewServer(
		makeReportChatroomMemberEndpoint(svc),
		makeDecodeReportChatroomMemberRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportLogHandler := kithttp.NewServer(
		makeReportLogEndpoint(svc),
		makeDecodeReportLogRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	reportHeartBeatHandler := kithttp.NewServer(
		makeReportHeartBeatEndpoint(svc),
		makeDecodeHeartBeatRequest(validate),
		kithttp.EncodeJSONResponse,
		opts...,
	)

	r := mux.NewRouter()
	r.Path("/api/v1/collector/report/message").Methods("POST").Handler(reportMessageHandler)
	r.Path("/api/v1/collector/report/upload").Methods("POST").Handler(reportUploadHandler)
	r.Path("/api/v1/collector/report/collector_join_chatroom").Methods("POST").Handler(reportCollectorJoinChatroomHandler)
	r.Path("/api/v1/collector/report/collector_leave_chatroom").Methods("POST").Handler(reportCollectorLeaveChatroomHandler)
	r.Path("/api/v1/collector/report/member_join_chatroom").Methods("POST").Handler(reportMemberJoinChatroomHandler)
	r.Path("/api/v1/collector/report/member_leave_chatroom").Methods("POST").Handler(reportMemberLeaveChatroomHandler)
	r.Path("/api/v1/collector/report/chatroom_members").Methods("POST").Handler(reportChatroomMemberHandler)
	r.Path("/api/v1/collector/report/log").Methods("POST").Handler(reportLogHandler)
	r.Path("/api/v1/collector/report/heartbeat").Methods("POST").Handler(reportHeartBeatHandler)
	return r
}

func normalizeMember(member *Member) {
	if len(member.Id) == 0 {
		return
	}
	switch member.Sex {
	case "0":
		member.Sex = "男"
	case "1":
		member.Sex = "女"
	default:
		member.Sex = "未知"
	}
}

func makeDecodeReportMessageRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(_ context.Context, r *http.Request) (interface{}, error) {
		var report MessageReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		report.DataSource = DefaultDataSource
		normalizeMember(&report.Member)
		normalizeMember(&report.Chatroom.Owner)
		return report, nil
	}
}

func makeDecodeReportUploadRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(_ context.Context, r *http.Request) (interface{}, error) {
		if err := r.ParseMultipartForm(1e6); err != nil {
			return nil, err
		}
		var data string
		if arr, exists := r.MultipartForm.Value["data"]; !exists || len(arr) == 0 {
			return nil, errors.New("data不存在")
		} else {
			data = arr[0]
		}
		var report MessageReport
		if err := json.Unmarshal([]byte(data), &report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		if len(report.Filename) == 0 {
			return nil, errors.New("文件名不存在")
		}
		report.DataSource = DefaultDataSource

		var fh *multipart.FileHeader
		if arr, exists := r.MultipartForm.File["file"]; !exists || len(arr) == 0 {
			return nil, errors.New("文件不存在")
		} else {
			fh = arr[0]
			report.FileSize = fh.Size
		}
		f, err := fh.Open()
		if err != nil {
			return nil, err
		}
		normalizeMember(&report.Member)
		normalizeMember(&report.Chatroom.Owner)
		request := UploadReport{
			MessageReport: report,
			File:          f,
		}
		return request, nil
	}
}

func makeDecodeReportCollectorJoinChatroomRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report CollectorJoinChatroomReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		report.Chatroom.DataSource = DefaultDataSource
		report.Chatroom.Owner.DataSource = DefaultDataSource
		normalizeMember(&report.Chatroom.Owner)
		return report, nil
	}
}

func makeDecodeReportCollectorLeaveChatroomRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report CollectorLeaveChatroomReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		report.Chatroom.DataSource = DefaultDataSource
		normalizeMember(&report.Chatroom.Owner)
		return report, nil
	}
}

func makeDecodeReportMemberJoinChatroomRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report MemberJoinChatroomReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		report.Chatroom.DataSource = DefaultDataSource
		report.Chatroom.Owner.DataSource = DefaultDataSource
		report.Member.DataSource = DefaultDataSource
		if len(report.Inviter.Id) > 0 {
			report.Inviter.DataSource = DefaultDataSource
		}
		normalizeMember(&report.Member)
		normalizeMember(&report.Chatroom.Owner)
		return report, nil
	}
}

func makeDecodeReportMemberLeaveChatroomRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report MemberLeaveChatroomReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return err, nil
		}
		report.Chatroom.DataSource = DefaultDataSource
		normalizeMember(&report.Member)
		normalizeMember(&report.Chatroom.Owner)
		return report, nil
	}
}

func makeDecodeReportChatroomMemberRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report ChatroomMemberReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		for i := 0; i < len(report.Chatrooms); i++ {
			report.Chatrooms[i].DataSource = DefaultDataSource
			normalizeMember(&report.Chatrooms[i].Owner)
			for j := 0; j < len(report.Chatrooms[i].Members); j++ {
				report.Chatrooms[i].Members[j].DataSource = DefaultDataSource
				normalizeMember(&report.Chatrooms[i].Members[j])
			}
		}
		return report, nil
	}
}

func makeDecodeReportLogRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report LogReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		return report, nil
	}
}

func makeDecodeHeartBeatRequest(validate *validator.Validate) kithttp.DecodeRequestFunc {
	return func(ctx context.Context, r *http.Request) (interface{}, error) {
		var report HeartBeatReport
		if err := json.NewDecoder(r.Body).Decode(&report); err != nil {
			return nil, err
		}
		if err := validate.Struct(report); err != nil {
			return nil, err
		}
		return report, nil
	}
}

func errorEncoder(_ context.Context, err error, w http.ResponseWriter) {
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
	_ = json.NewEncoder(w).Encode(map[string]string{"error": err.Error()})
}
